package com.yxt.gateway.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.*;
import org.springframework.http.server.RequestPath;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 全局过滤器 :用于鉴权(获取令牌 解析 判断)
 *
 */
@Component
@Slf4j
public class TokenFilter implements GlobalFilter, Ordered {
    private static final String AUTHORIZE_TOKEN = "Authorization";
    private static final String REFRESH_TOKEN = "refreshToken";

    @Value("${auth.clientId}")
    private String clientId;

    @Value("${auth.clientSecret}")
    private String clientSecret;

    @Value("${auth.cookieDomain}")
    private String cookieDomain;

    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @Value("#{'${whiteList}'.split(',')}")
    private String[] whiteList;

    @Autowired
    private RestTemplate restTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1.获取请求对象
        ServerHttpRequest request = exchange.getRequest();
        log.info("getPath: "+request.getPath());
        log.info("getURI111: "+request.getURI());
        RequestPath path = request.getPath();

        //2.获取响应对象
        ServerHttpResponse response = exchange.getResponse();

        //白名单一律放行
        PathMatcher matcher = new AntPathMatcher();
        if(whiteList!=null){
            List<String> whiteLists = Arrays.asList(whiteList);
            for(String item: whiteLists)
            {
                if(matcher.match(item,path.toString())){
                    return chain.filter(exchange);
                }
            }
        }


        //从请求头中获取令牌数据
        String token = request.getHeaders().getFirst(AUTHORIZE_TOKEN);
        if(StringUtils.isEmpty(token)){
            //从cookie中中获取令牌数据
            //String cookieValue = request.getCookies().getFirst(AUTHORIZE_TOKEN).getValue();
            HttpCookie authorizeToken = request.getCookies().getFirst(AUTHORIZE_TOKEN);
            if(!StringUtils.isEmpty(authorizeToken)){
                token="Bearer "+authorizeToken.getValue();
                request.mutate().header(AUTHORIZE_TOKEN,token);
            }else{
                log.info("custom global refreshTokenValuerefreshTokenValuerefreshTokenValue");
                //如果还为空，考虑是token过期。
                HttpCookie refreshTokenValue = request.getCookies().getFirst(REFRESH_TOKEN);

                if( !StringUtils.isEmpty(refreshTokenValue)) {
                    ServiceInstance serviceInstance = loadBalancerClient.choose("auth-service");

                    if (serviceInstance == null) {
                        throw new RuntimeException("找不到对应的服务");
                    }
                    String url =serviceInstance.getUri().toString()+"/oauth/token";
                    //2.定义头信息 (有client id 和client secr)
                    MultiValueMap<String,String> headers = new LinkedMultiValueMap<>();
                    headers.add("Authorization",httpbasic(clientId, clientSecret));
                    //3. 定义请求体  有授权模式 用户的名称 和密码
                    MultiValueMap<String,String> formData = new LinkedMultiValueMap<>();
                    formData.add("grant_type","refresh_token");
                    formData.add("refresh_token", refreshTokenValue.getValue());
                    //4.模拟浏览器 发送POST 请求 携带 头 和请求体 到认证服务器
                    HttpEntity<MultiValueMap> requestentity = new HttpEntity<MultiValueMap>(formData,headers);
                    ResponseEntity<Map> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestentity, Map.class);
                    //5.接收到返回的响应(就是:令牌的信息)
                    Map body = responseEntity.getBody();
                    String accessToken = (String) body.get("access_token");
                    String refreshToken = (String) body.get("refresh_token");
                    Integer expiresIn= (Integer) body.get("expires_in");
                    //设置到cookie中
                    //acccestoken
                    response.addCookie(ResponseCookie.from("Authorization", accessToken).path("/").domain(cookieDomain).maxAge(expiresIn).build());
                    //refreshtoken
                    response.addCookie(ResponseCookie.from("refreshToken", refreshToken).path("/").domain(cookieDomain).maxAge(2592000).build());
                    token="Bearer "+accessToken;
                    request.mutate().header(AUTHORIZE_TOKEN,token);
                } else {
                    response.setStatusCode(HttpStatus.UNAUTHORIZED);
                    return response.setComplete();
                }
            }
        }

        return chain.filter(exchange);
    }


    private String httpbasic(String clientId,String clientSecret){
        //将客户端id和客户端密码拼接，按“客户端id:客户端密码”
        String string = clientId+":"+clientSecret;
        //进行base64编码
        byte[] encode = Base64Utils.encode(string.getBytes());
        return "Basic "+new String(encode);
    }

    @Override
    public int getOrder() {
        return 1;
    }
}
